package cn.elegent.lock.strategy.redis;
import cn.elegent.lock.ELegentLock;
import cn.elegent.lock.config.RedisLockConfig;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.RedissonRedLock;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;

/**
 * redis分布式锁实现类
 */
@ConditionalOnProperty(prefix = "elegent.lock",name = "type",havingValue = "redis")
@Slf4j
public class RedisLock implements ELegentLock {

    private RedissonClient redissonClient;

    @Autowired
    private RedisLockConfig redisLockConfig;


    @PostConstruct
    public void init(){
        Config config = new Config();
        config.useSingleServer().setAddress("redis://"+redisLockConfig.getHost()+":"+redisLockConfig.getPort());
        this.redissonClient = Redisson.create(config);
        log.info("redis连接成功");

    }


    /**
     * 加锁
     *
     * @param lockName
     */
    public boolean lock(String lockName) {
        RLock lock = redissonClient.getLock(lockName);
        if(redisLockConfig.isRenewal()){  //如果续期
            lock.lock(-1,TimeUnit.SECONDS);  //-1 启动看门狗
        }else{
            lock.lock(redisLockConfig.getTtl(),TimeUnit.SECONDS);
        }
        log.info("redis加锁成功，锁名称：{}",lockName);
        return true;
    }


    /**
     * 尝试获取锁
     *
     * @param lockName
     * @return
     */
    public boolean tryLock(String lockName) {
        RLock lock = redissonClient.getLock(lockName);
        boolean isLock=lock.isLocked();
        if(isLock) return false;
        try {
            if(redisLockConfig.isRenewal()) {  //如果续期
                isLock= lock.tryLock(redisLockConfig.getWait(),-1,TimeUnit.SECONDS);//-1 启动看门狗
            }else{
                isLock= lock.tryLock(redisLockConfig.getWait(),redisLockConfig.getTtl(),TimeUnit.SECONDS);
            }
            if(isLock){
                log.info("redis加锁成功，锁名称：{}",lockName);
            }else{
                log.info("redis加锁失败，锁名称：{}",lockName);
            }
            return isLock;
        } catch (InterruptedException e) {
            e.printStackTrace();
            log.info("redis加锁出错，锁名称：{}",lockName);
            return false;
        }
    }


    /**
     * 释放锁
     *
     * @param lockName
     */
    public boolean unLock(String lockName) {
        try {
            RLock lock = redissonClient.getLock(lockName);
            lock.unlock();
            log.info("redis释放锁成功，锁名称：{}",lockName);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            log.info("redis释放锁出错，锁名称：{}",lockName);
            return false;
        }
    }

    /**
     * 是否存在锁
     *
     * @param lockName
     * @return
     */
    public boolean isLocked(String lockName) {
        RLock lock = redissonClient.getLock(lockName);
        return lock.isLocked();
    }
}
